﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using SDF.Pagination;
using System.Windows.Media;

namespace SDF
{
    public class SmartPage : SmartTextElement
    {
        #region Constructor

        public SmartPage()
        {
            PaginationInfo = new PaginationInfo();

            ColumnGrid = new Grid();
            ColumnGrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
            ColumnGrid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Star) });
            ColumnGrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });

            ColumnCount = 1;
            ColumnWidth = 0;
            ShowHeader = true;
            ShowFooter = true;

            Columns = new List<PageContent>();
        }

        public SmartPage(SmartDocument document): this()
        {
            Document = document;
        }

        public SmartPage(SmartDocument document, Size pageSize, Thickness margin, int columns, double columnWidth): this(document)
        {
            ColumnCount = columns;
            ColumnWidth = columnWidth;
            Margin = margin;
            PageSize = pageSize;
        }

        #endregion

        #region Properties

        public SmartDocument Document { get; set; }

        public Thickness Margin { get; set; }

        public Size PageSize { get; set; }

        public int ColumnCount { get; set; }

        public double ColumnWidth { get; set; }

        public List<PageContent> Columns { get; private set; }

        public bool ShowHeader
        {
            get
            {
                //if (HeaderTemplate == null)
                //    return false;

                return _ShowHeader;
            }
            set
            {
                _ShowHeader = value;
            }
        }
        private bool _ShowHeader;

        public bool ShowFooter
        {
            get
            {
                //if (FooterTemplate == null)
                //    return false;

                return _ShowFooter;
            }
            set
            {
                _ShowFooter = value;
            }
        }
        private bool _ShowFooter;

        public PaginationInfo PaginationInfo { get; private set; }

        public Grid ColumnGrid { get; private set; }

        #endregion

        #region Visual Children Implementation

        protected override int VisualChildrenCount
        {
            get { return 1; }
        }

        protected override Visual GetVisualChild(int index)
        {
            if (index < 0 || index >= 1)
                throw new ArgumentOutOfRangeException("index");

            return ColumnGrid;
        }

        #endregion

        #region Layout Methods

        protected override Size MeasureCore(Size availableSize)
        {
            SetupGrid();

            ColumnGrid.Measure(availableSize);
            return ColumnGrid.DesiredSize;
        }

        private void SetupGrid()
        {
            Background = Document.Background;
            FlowDirection = Document.FlowDirection;
            FontFamily = Document.FontFamily;
            FontSize = Document.FontSize;
            FontStretch = Document.FontStretch;
            FontStyle = Document.FontStyle;
            FontWeight = Document.FontWeight;
            Foreground = Document.Foreground;

            Thickness margin = CalculateActualMargin();

            ColumnGrid.Margin = new Thickness(margin.Left, 0, margin.Right, 0);

            ColumnGrid.RowDefinitions[0].Height = new GridLength(margin.Top);
            ColumnGrid.RowDefinitions[2].Height = new GridLength(margin.Bottom);

            var gridSize = PageSize.Subtract(ColumnGrid.Margin);
            
            ColumnGrid.Width = gridSize.Width;
            ColumnGrid.MaxWidth = gridSize.Width;
            ColumnGrid.Height = gridSize.Height;
            ColumnGrid.MaxHeight = gridSize.Height;

            // Calculate the column gap. If not specified, assume 1 times the line height, like Microsoft does
            // http://msdn.microsoft.com/en-us/library/system.windows.documents.flowdocument.columngap.aspx
            double columnGap = Document.ColumnGap;
            if (double.IsNaN(columnGap) || double.IsInfinity(columnGap))
                columnGap = Document.LineHeight;

            ColumnGrid.ColumnDefinitions.Clear();
            for (int i = 0; i < ColumnCount; i++)
            {
                var columnDefinition = new ColumnDefinition()
                {
                    Width = new GridLength(ColumnWidth)
                };
                ColumnGrid.ColumnDefinitions.Add(columnDefinition);

                if (i < ColumnCount - 1)
                {
                    // Add the gap too
                    var gapColumnDefinition = new ColumnDefinition()
                    {
                        Width = new GridLength(columnGap)
                    };
                    ColumnGrid.ColumnDefinitions.Add(gapColumnDefinition);
                }
            }

            ColumnGrid.Children.Clear();

            int position = 0;
            while (position < ColumnCount)
            {
                PageContent content = null;
                if (position < Columns.Count)
                {
                    content = Columns[position];
                    Grid.SetColumn(content, position * 2);
                    Grid.SetRow(content, 1);
                    ColumnGrid.Children.Add(content);

                    if ((position > 0) && (content != null))
                    {
                        // Add the rule
                        var rule = new Border()
                        {
                            Width = Document.ColumnRuleWidth,
                            Background = Document.ColumnRuleBrush,
                            HorizontalAlignment = HorizontalAlignment.Center
                        };
                        Grid.SetColumn(rule, (position * 2) - 1);
                        Grid.SetRow(rule, 1);
                        ColumnGrid.Children.Add(rule);
                    }
                }
                position++;
            }
        }


        protected virtual Thickness CalculateActualMargin()
        {
            double left = Margin.Left;
            double top = Margin.Top;
            double right = Margin.Right;
            double bottom = Margin.Bottom;

            if (double.IsNaN(left))
                left = LineHeight;
            if (double.IsNaN(top))
                top = LineHeight;
            if (double.IsNaN(right))
                right = LineHeight;
            if (double.IsNaN(bottom))
                bottom = LineHeight;

            return new Thickness(left, top, right, bottom);
        }

        protected override void ArrangeCore(Rect finalRect)
        {
            ColumnGrid.Arrange(finalRect);
            RenderSize = ColumnGrid.RenderSize;
        }

        #endregion

        #region AddContent

        public bool AddContent(PageContent content)
        {
            Columns.Add(content);
            return Columns.Count == ColumnCount;
        }

        #endregion

        #region Render Method

        public void Render()
        {
            Measure(PageSize);

            Rect pageBounds = new Rect(PageSize);
            Arrange(pageBounds);
        }

        #endregion

    }
}
